#include "system.h"
#include "synch.h"
#include <iostream>
#define MAX_CLERKS 3
#define MAX_CR 3
#define MAX_ITEM_TYPES 10  //this is fixed
#define MAX_STOCKBOYS 3
#define MAX_AISLES 10   //this is fixed
#define MAX_PRICE 100  
#define CUSTOMER_NUM 20
#define COUNT_FLOOR 10  
//if any item is less than this number, it needs to be restocked

void printInitialStatement();
void printtheResult();
void generate_item(int &, int &, int &,int *,int);

using namespace std;

Lock clerkLineLock("clerkLineLock");
//Lock for access the line length information
Lock managerLock("managerLock");
Lock clerkLock[MAX_CLERKS];
Lock cashRegisterLock[MAX_CR];
Condition clerkCV[MAX_CLERKS];
Condition cashRegisterCV[MAX_CR];
Condition clerkLineCV[MAX_CLERKS];
Condition clerkBreakCV[MAX_CLERKS];
Condition noClerkCV("noClerkCV");

Condition needMoneyCV[MAX_CR];

Lock clerkStateLock("clerkStateLock");

Lock aisleHelpLock[MAX_AISLES];
Condition aisleHelpCV[MAX_AISLES];
Lock aisleLock[MAX_AISLES];
Lock sbStatusLock("sbStatusLock");
Lock sbLock[MAX_STOCKBOYS];
Lock srLock("srLock");
Lock srLineLock("srLineLock");
Condition sbCV[MAX_STOCKBOYS];
Condition sbWakeCV[MAX_STOCKBOYS];


int clerkState[MAX_CLERKS]={0}; //not on break initially(=0)
int clerkLineLength[MAX_CLERKS]={0}; //Assume that all lines are empty initially
int sbStatus[MAX_STOCKBOYS];//(-1 when not on break;-2 when is working, but not in aisles)
int start_scanning[MAX_CLERKS]={0}; //if the clerk start scanning items
int finish_scanning[MAX_CLERKS]={0};//if the clerk finish scanning
int nextItem[MAX_CLERKS];//items that customer passes to clerk 
int amountofNextItem[MAX_CLERKS];//Amount of next item
int scanItemType[MAX_CR];//item that is being scanning
int scanItemAmount[MAX_CR];//amount of item that is being scanning
int totalPrice[MAX_CR]={0};//for displaying total price
int moneyInDrawer[MAX_CR]={0};//total money in the cashregister
int crSale[MAX_CR]={0};//sale amount of cashRegister(return to 0 if being emptied)
int crTotalSale[MAX_CR]={0};//total sale of cash register
int withDraw[MAX_CR]={0};//check if manager has withdrawed
int moreItem[MAX_CLERKS];//if there are more items to be scanned
int aisleHelpLine[MAX_AISLES]={0,0,0,0,0,0,0,0,0,0};
int price[MAX_ITEM_TYPES];//price for differnt items
int myAisle[MAX_STOCKBOYS];//manager use this to let stockboys know where to go
int itemOnAisle[MAX_AISLES]={3,3,3,3,3,3,3,3,3,3};//item amount on shelves
int itemToFind[MAX_STOCKBOYS];
//customers use this to tell stockboy which item they want to find
int toAisle[MAX_STOCKBOYS];
//stockboy use this to tell customer where the item is
int c_ID_c[MAX_CLERKS];//used to pass the customer ID to clerks and CR
int c_ID_s[MAX_STOCKBOYS];//used to pass customer ID to stockboys
int num_sb_in_sr=0;//number of stockboy in stockroom
int sb_in_sr=-1;//store the index of stockboy which is in the stockroom
int serviceButton=0;
int moreClerk[MAX_CLERKS]={0};
//the value 1 denotes clerk[index] has called manager
int noClerk=0;
//this value means how many customers has called manager
int noMoney[MAX_CR]={0};
//equals 1 if CR needs money
int needSB[MAX_AISLES]={0};
//value 1 means item on the shelf is not enough
int customerType[MAX_CLERKS]={0};
//1=buy item, -1=return item
int customerInStore=CUSTOMER_NUM;


extern int seed;//random seed, defined in main

void customer(int myIndex)
{
  
  int shortestLineIndex = -1;
  int shortestLineLength = 999;
  int item[MAX_ITEM_TYPES]={0};
  //storage the amount of each kind of item to buy
  int numofTotalItem=0;
  int numofItemTypes=0;  
  int myType;
  int tempM=0;

  srand(seed*5+myIndex);
  myType=(rand()%5);
  
  generate_item(numofTotalItem,numofItemTypes,tempM,item,myIndex);
   

  
  //have generated all items;ready to take items
  
  //I am going to buy items
  if(myType>0)
  { 
    printf("Customer [%d] wants to buy [%d] no. of items.\n",
	   myIndex+1,numofTotalItem);
    myType=1;
    //looking for items or the help of stockboy
    int ifFind;
    for(int x=0;x<MAX_ITEM_TYPES;x++)
    { 
      if(item[x]==0)//skip the item that didn't buy
        continue;     
 
      int noItem=1;
      ifFind=(rand()%4);//0=can't find the item;1~3=can find the item
      while(noItem==1)//haven't got the item
      { 
        if(ifFind==0)//can't find the item
	{
          int findItem=x;//item that can not find    
          printf("Customer [%d] is not able to find item [%d] and is searching for StockBoy.\n",
	          myIndex+1, findItem+1);
          int findSb=0;//0:has not found StockBoy yet 
          while(findSb==0)
          {
            int helpAisle=-1;
            for(int i=0;i<MAX_AISLES;i++)
            {
              aisleHelpLock[i].Acquire();
              sbStatusLock.Acquire();
              for(int j=0;j<MAX_STOCKBOYS;j++)
              { 
                if((sbStatus[j]%10)==i&&sbStatus[j]>=0)
                {
                  helpAisle=i;
                  aisleHelpLine[helpAisle]++;
                  break;
                }
              } 
              sbStatusLock.Release();
              if(helpAisle>=0)
                break;
              aisleHelpLock[i].Release();
            }
            //if I didn't find a stockboy
            if(helpAisle==-1)
            {
              //do service button stuff
              managerLock.Acquire();
              serviceButton=1;      
              printf("Customer [%d] looked in all aisle for StockBoy. He is now requesting help by pressing service button.\n",myIndex+1);   
                      managerLock.Release();
              for(int i=0;i<10;i++)
                currentThread->Yield();
            }
            else
            {
              //found a stock boy in an aisle
              findSb=1;      
              //  sbStatusLock->Release();
              aisleHelpCV[helpAisle].Wait(&aisleHelpLock[helpAisle]);
              //now find an avaible stockboy
              sbStatusLock.Acquire();
              aisleHelpLock[helpAisle].Release();
              int myStockBoy;
              //search the array for helpAisle+10.
              for(int i=0;i<MAX_STOCKBOYS;i++)
              {
                if(sbStatus[i]==(helpAisle+10))
                {
                  myStockBoy=i;
                  sbStatus[i]=sbStatus[i]-10;
                  break;
                }  
              }
        
              //Subtract 10 from their value
              sbStatusLock.Release();
              sbLock[myStockBoy].Acquire();
              //set my item # in a stockboy specific monitor variable,
              //signal the stockboy and then wait for the aisle number
              itemToFind[myStockBoy]=findItem;
              printf("Customer [%d] is asking for assistance from StockBoy [%d].\n",
	              myIndex+1, myStockBoy+1);
              c_ID_s[myStockBoy]=myIndex;
              sbCV[myStockBoy].Signal(&sbLock[myStockBoy]);
              sbCV[myStockBoy].Wait(&sbLock[myStockBoy]);
              printf("Customer [%d] got aisle [%d] from StockBoy [%d].\n", 
  	              myIndex+1,toAisle[myStockBoy]+1,myStockBoy+1);
              sbLock[myStockBoy].Release(); 
              ifFind=1;//have found the item
            }
          }
        }
        else//find the item by itself, but hasn't got the item
	{
          aisleLock[x].Acquire();
          if(itemOnAisle[x]<item[x])//item on the shelf is not enough
          { 
            needSB[x]=1;
            aisleLock[x].Release(); 
            for(int n=0;n<20;n++)
	      currentThread->Yield();
          }
          else
          { 
            itemOnAisle[x]=itemOnAisle[x]-item[x];
            noItem=0;//I already got the item
            aisleLock[x].Release(); 
          }
        }
      }
    }
  }
  else//I am going to return items
  {
    printf("Customer [%d] needs to return [%d] no.of items.\n",
	   myIndex+1,numofTotalItem);
  }
 
  //grab all items, search the shortest line with clerk
  
  while(shortestLineIndex==-1)
  {
    clerkLineLock.Acquire();
    for(int i=0;i<MAX_CLERKS;i++)
    { 
      managerLock.Acquire();
      if(clerkState[i]==1)//check if the clerk is on break
      {
	managerLock.Release();  
        continue;
      }
       managerLock.Release();
      //clerk is not on break, check line length
      if(clerkLineLength[i]<shortestLineLength)
      {
        shortestLineLength = clerkLineLength[i];
        shortestLineIndex = i;
      }
    }
    //Are all clerks on break?
    if(shortestLineIndex==-1)
    {
      //handle it!
      clerkLineLock.Release();
      managerLock.Acquire();
      noClerk++;
      noClerkCV.Wait(&managerLock);
      managerLock.Release();
      continue;
    }
  }
  //get in line
  printf("Customer [%d] chose Clerk [%d] with line length of [%d].\n",myIndex+1, 
	 shortestLineIndex+1, shortestLineLength);
  clerkLineLength[shortestLineIndex]++;
  clerkLineCV[shortestLineIndex].Wait(&clerkLineLock);
  //wait for clerk calling
  clerkLineLength[shortestLineIndex]--;
  
  clerkLineLock.Release();

  clerkLock[shortestLineIndex].Acquire();  
  
  c_ID_c[shortestLineIndex]=myIndex;//tell clerk my ID
  
  int type=0;  // start giving item to clerk from first item
  int itemsLeft=numofItemTypes;
  customerType[shortestLineIndex]=myType;  
  
  while(itemsLeft!=0) //if there are items need to be scanned
  {
    if(item[type]==0)//none of this item
    {
      type++; //increment the index for item array
      continue;  //see next item
    }
  
    //give item to clerk 
    nextItem[shortestLineIndex]=type;
    amountofNextItem[shortestLineIndex]=item[type];
    printf("Customer [%d] gives item [%d] to Clerk [%d].\n", myIndex+1, type+1,
	   shortestLineIndex+1);
    if(itemsLeft==1)
    {
      moreItem[shortestLineIndex]=0;//the last item
      printf("Customer [%d] tells Clerk [%d], I have given you all my [%d] items.\n", myIndex+1, shortestLineIndex+1, numofItemTypes);
    }
    clerkCV[shortestLineIndex].Signal(&clerkLock[shortestLineIndex]);
    itemsLeft--;
    //wait for giving next type of item(s)   
    clerkCV[shortestLineIndex].Wait(&clerkLock[shortestLineIndex]);
    type++;
  }
  clerkCV[shortestLineIndex].Signal(&clerkLock[shortestLineIndex]);
  //get the price from clerk
  clerkCV[shortestLineIndex].Wait(&clerkLock[shortestLineIndex]);
  if(myType>0)
  {
    //paying
    clerkCV[shortestLineIndex].Signal(&clerkLock[shortestLineIndex]);
    printf("Customer [%d] pays [%d] to Clerk [%d] and is now waiting for receipt.\n",
	    myIndex+1, totalPrice[shortestLineIndex], shortestLineIndex+1);
  }
  else
  {
    clerkCV[shortestLineIndex].Signal(&clerkLock[shortestLineIndex]);
    //return item
    clerkCV[shortestLineIndex].Wait(&clerkLock[shortestLineIndex]);  
    printf("Customer [%d] receives [%d] from Clerk [%d] and is now waiting for receipt.\n",
	   myIndex+1, totalPrice[shortestLineIndex], shortestLineIndex+1);
    clerkCV[shortestLineIndex].Signal(&clerkLock[shortestLineIndex]);
  }
  //wait for the receipt
  clerkCV[shortestLineIndex].Wait(&clerkLock[shortestLineIndex]);
  printf("Customer [%d] got reciept from Clerk [%d] and is now leaving.\n", 
	 myIndex+1, shortestLineIndex+1);
  //Leave the store
  clerkCV[shortestLineIndex].Signal(&clerkLock[shortestLineIndex]);
  clerkLock[shortestLineIndex].Release();
  
}

void clerk(int myIndex)
{
  while(1)
  {
    clerkLineLock.Acquire();
    if(clerkLineLength[myIndex]>0)
    {
      //I have customers in my line, wake one up
      if(clerkLineLength[myIndex]>4)//need more clerks
      {
        managerLock.Acquire();
        moreClerk[myIndex]=1;
        printf("Clerk [%d] sees more than 4 people in line and calls Manager.\n",
	       myIndex+1);
        managerLock.Release();
        
      }
      clerkLineCV[myIndex].Signal(&clerkLineLock);
    }
    else
    {
      //I go on break
      printf("Clerk [%d] is leaving Cash Register [%d] and go on break.\n", 
	     myIndex+1, myIndex+1);
      clerkLineLock.Release();
      managerLock.Acquire();
      clerkState[myIndex]=1;
      //wait for manager calling
      clerkBreakCV[myIndex].Wait(&managerLock);
      printf("Clerk [%d] was called by Manager to work.\n", myIndex+1);
      managerLock.Release();
      for(int i=0;i<10;i++)
        currentThread->Yield();
      continue;
      //wait for manager calling
      
    }
    //Acquire the lock before customer
    clerkLock[myIndex].Acquire();
    moreItem[myIndex]=1;
    clerkLineLock.Release();
    
    cashRegisterLock[myIndex].Acquire();
    start_scanning[myIndex]=1;
    finish_scanning[myIndex]=0;
    //power on the cashregister
    cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]);  
    //wait for CashRegister ready
    cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]); 
    
    while(moreItem[myIndex]==1)
    {
      //wait for customer to give me item(s)
      clerkCV[myIndex].Wait(&clerkLock[myIndex]);
      //get item type from customer
      printf("Clerk [%d] got item [%d] from Customer [%d].\n", myIndex+1,
	     nextItem[myIndex]+1, c_ID_c[myIndex]+1);
      //scan the items
      scanItemType[myIndex]=nextItem[myIndex];
      scanItemAmount[myIndex]=amountofNextItem[myIndex];
      if(moreItem[myIndex]==0)
        finish_scanning[myIndex]=1;
      printf("Clerk [%d] gave item [%d] to Cash Register [%d] for scanning.\n",
	     myIndex+1, scanItemType[myIndex]+1, myIndex+1);
      cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]);
      //wait for a scanning process
      cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]);
      //tell the customer to give next type of item(s)
      clerkCV[myIndex].Signal(&clerkLock[myIndex]);
    }
    //ask CashRegister to calculate the total value
    cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]);
    // start_scanning[myIndex]=0;
    //wait for the cashRegister displaying the price
    cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]);
    //get the price from cash register
    printf("Clerk [%d] got total cost $[%d] from Cash Register [%d].\n", 
	   myIndex+1, totalPrice[myIndex], myIndex+1);
    //wait for telling customer the total price
    clerkCV[myIndex].Wait(&clerkLock[myIndex]);
    //tell customer the total price-handle it
    clerkCV[myIndex].Signal(&clerkLock[myIndex]);
    printf("Clerk [%d] tells Customer [%d] total cost is $[%d].\n",
	   myIndex+1, c_ID_c[myIndex]+1,totalPrice[myIndex]);
    if(customerType[myIndex]>0)//customer is buying items
    {
      //wait for customer paying
      clerkCV[myIndex].Wait(&clerkLock[myIndex]); 
      printf("Clerk [%d] got money $[%d] from Customer [%d].\n", myIndex+1,
	     totalPrice[myIndex],c_ID_c[myIndex]+1);
      //deposit money into cashregister
      moneyInDrawer[myIndex]+=totalPrice[myIndex];    
      cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]); 
      printf("Clerk [%d] gave the money $[%d] to Cash Register [%d].\n",
	     myIndex+1, totalPrice[myIndex], myIndex+1);
    }
    else//customer is returning items
    { //wait for confirmation from customer
      clerkCV[myIndex].Wait(&clerkLock[myIndex]);
      cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]);
      cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]);
      printf("Clerk [%d] got money $[%d] from Cash Register [%d].\n",myIndex+1,
	     totalPrice[myIndex], myIndex+1);
      moneyInDrawer[myIndex]=moneyInDrawer[myIndex]-totalPrice[myIndex];
      cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]);
      clerkCV[myIndex].Signal(&clerkLock[myIndex]);
      printf("Clerk [%d] gave the money $[%d] to Customer [%d].\n", myIndex+1,
	     totalPrice[myIndex],c_ID_c[myIndex]+1);
      clerkCV[myIndex].Wait(&clerkLock[myIndex]);
    }
    //wait for the receipt
    cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]); 
    printf("Clerk [%d] got receipt from Cash Register [%d].\n",
	     myIndex+1, myIndex+1);
    //stop using the cashregister
    
    finish_scanning[myIndex]=0;
    cashRegisterLock[myIndex].Release();
    //give receipt to customer
    clerkCV[myIndex].Signal(&clerkLock[myIndex]);
    printf("Clerk [%d] gave the receipt to Customer [%d] and tells him to leave.\n",
	   myIndex+1,c_ID_c[myIndex]+1);
    //wait for customer leaving
    clerkCV[myIndex].Wait(&clerkLock[myIndex]);  
    //finish serving this customer
    clerkLock[myIndex].Release();
  }
}

void cashRegister(int myIndex)
{
  while(1)
  {
    int itemCount=0;
    cashRegisterLock[myIndex].Acquire();
    if(start_scanning[myIndex]==1)
    {
      //Let the clerk know it is ready for scanning
      cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]);
      while(finish_scanning[myIndex]==0)
      {
        cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]);
        itemCount++;
   
        totalPrice[myIndex]+=(price[scanItemType[myIndex]]*scanItemAmount[myIndex]);
        printf("Cash Register [%d] got item [%d] from Clerk [%d] to scan.\n",
	       myIndex+1, scanItemType[myIndex]+1, myIndex+1);
        cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]);
      }
      //wait for clerk finishing scanning items
      printf("Cash Register [%d] has scanned all [%d] items for Customer [%d].\n",
	     myIndex+1, itemCount, c_ID_c[myIndex]+1);
      cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]);
      //display the total price
      cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]);
      printf("Cash Register [%d] gave total cost $[%d] for Customer [%d] to Clerk [%d] for [%d] items.\n", myIndex+1, totalPrice[myIndex], c_ID_c[myIndex]+1, myIndex+1, itemCount);

      
      if(customerType[myIndex]>0)//wait for money
      {
        //wait for the cash deposit
        cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]);
        printf("Cash Register [%d] got the money from Clerk [%d].\n", myIndex+1, 
	       myIndex+1);
        crSale[myIndex]+=totalPrice[myIndex];
        crTotalSale[myIndex]+=totalPrice[myIndex];
      }
      else//give money to customer
      {
        cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]);
        //if money in drawer is not enough
        if(totalPrice[myIndex]>moneyInDrawer[myIndex])  
	{ 
          int balance=totalPrice[myIndex]-moneyInDrawer[myIndex];
         
	  noMoney[myIndex]=1;
          printf("Cash Register [%d] informed the manager that he needs $[%d].\n",
		 myIndex+1, balance);
          needMoneyCV[myIndex].Wait(&cashRegisterLock[myIndex]);  
          printf("Cash Register [%d] received $[%d] from the manager.\n",
		 myIndex+1, balance);          
        }
        cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]);
        printf("Cash Register [%d] gave the money from Clerk [%d].\n",
	       myIndex+1,myIndex+1);
        //wait for clerk taking the money
        cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]);
        //crSale[myIndex]=crSale[myIndex]-totalPrice[myIndex];
        //crTotalSale[myIndex]=crTotalSale[myIndex]-totalPrice[myIndex];
      } 
      //give receipt to clerk
      cashRegisterCV[myIndex].Signal(&cashRegisterLock[myIndex]); 
      printf("Cash Register [%d] gave receipt to Clerk [%d] for Customer [%d].\n",
	     myIndex+1, myIndex+1, c_ID_c[myIndex]+1);
      printf("Cash Register [%d] total sale is $[%d].\n", myIndex+1,
	     crSale[myIndex]);
      start_scanning[myIndex]=0;  
      totalPrice[myIndex]=0;
      itemCount=0;
      customerInStore--;
    }
    while(start_scanning[myIndex]!=1)
    {
      // printf("Cash Register [%d] is waiting for clerk's signal.\n", myIndex+1);
      cashRegisterCV[myIndex].Wait(&cashRegisterLock[myIndex]);//standby
      if(withDraw[myIndex]==1)//if the manager took the money
      {
        printf("Cash Register [%d] drawer is emptied by Manager.\n",myIndex+1);
        printf("Cash Register [%d] total sale until now is $[%d].\n",myIndex+1,
  	       crTotalSale[myIndex]);  
        withDraw[myIndex]=0;
      }
    }
    cashRegisterLock[myIndex].Release();
  }
}


void stockboy(int myIndex)
{ 
  int reStockAisle=-1;//0~9: index for restock aisle;100:go help customer
  while(1)
  {
    sbStatusLock.Acquire();
    if(reStockAisle==-1)//No more items to be restocked
    {
      
      sbStatus[myIndex]=-1;
      printf("StockBoy [%d] is going on break.\n",myIndex+1);
      sbWakeCV[myIndex].Wait(&sbStatusLock);
      //wait for manager waking up
      sbStatus[myIndex]=-2; 
      printf("StockBoy [%d] got call from Manager.\n",myIndex+1);
      //exit the stock room-go to myAisle
      //sbStatusLock->Acquire();
      //manager set myAisle here
      reStockAisle=myAisle[myIndex];
      printf("StockBoy [%d] retrieve one new item [%d] from stock room.\n",myIndex+1, myAisle[myIndex]+1);
    }
    sbStatusLock.Release();

    if(reStockAisle<10) 
    {
      srLineLock.Acquire();//enter the stock waiting line
      num_sb_in_sr++;
      if(num_sb_in_sr>1)
        printf("StockBoy [%d] is waiting for StockBoy [%d] to leave the stock room.\n",
	        myIndex+1, sb_in_sr+1);
      sb_in_sr=myIndex;
      srLock.Acquire();
      printf("StockBoy [%d] is in stock room.\n",myIndex+1);
      srLineLock.Release();
    
      currentThread->Yield();
      //get the item
      num_sb_in_sr--;
      printf("StockBoy [%d] leaves stock room.\n",myIndex+1);
      srLock.Release();
    }
    //Set the status in aisle so that customer can find
    sbStatusLock.Acquire();  
    sbStatus[myIndex]=(reStockAisle%10);
    sbStatusLock.Release();
      //in the Aisle
    for(int i=0;i<15;i++)//wait some time to let customers find them
    {
      currentThread->Yield();
    }
    //restock item code here
    if(reStockAisle<10)
    {
      aisleLock[reStockAisle].Acquire();
      itemOnAisle[reStockAisle]++;  
      printf("StockBoy [%d] restock item [%d].\n",myIndex+1,reStockAisle+1);
      aisleLock[reStockAisle].Release();
    }
    reStockAisle=(reStockAisle%10);
    //check for customers needing help
    aisleHelpLock[reStockAisle].Acquire();
    while(aisleHelpLine[reStockAisle]>0)
    {
      //there is customer needing help
      aisleHelpCV[reStockAisle].Signal(&aisleHelpLock[reStockAisle]);
      aisleHelpLine[reStockAisle]--;
      sbStatusLock.Acquire();
      aisleHelpLock[reStockAisle].Release();
      //stockboy must change their status so customer knows they are ready to 
      //help in the customer aisle
      sbStatus[myIndex]=sbStatus[myIndex]+10;
      sbLock[myIndex].Acquire();
      sbStatusLock.Release();
      sbCV[myIndex].Wait(&sbLock[myIndex]);
      //stockboy is waiting for the customer needed item number
      printf("StockBoy [%d] is approached by Customer [%d] for assistance.\n",
  	     myIndex+1,c_ID_s[myIndex]+1);
      toAisle[myIndex]=itemToFind[myIndex];
      //give the index of the shelf that has the item
      printf("StockBoy [%d] gave aisle [%d] to Customer [%d] for item [%d].\n",
	     myIndex+1,toAisle[myIndex]+1,c_ID_s[myIndex]+1,itemToFind[myIndex]+1);
      sbCV[myIndex].Signal(&sbLock[myIndex]);
      sbLock[myIndex].Release();
      aisleHelpLock[reStockAisle].Acquire();
    }
    sbStatusLock.Acquire();
    sbStatus[myIndex]=-2;//set state to busy(not available)
    sbStatusLock.Release();
    aisleHelpLock[reStockAisle].Release();

    //finish helping customer, check if more items are to be restocked
    printf("StockBoy [%d] is checking if more items are to be re-stocked.\n",
	   myIndex+1);
    for(int i=0;i<MAX_AISLES;i++)
    {
      aisleLock[i].Acquire();
      if(itemOnAisle[i]<COUNT_FLOOR)
      {
        reStockAisle=i;
        printf("StockBoy [%d] goes back to stock room for item [%d].\n",
	       myIndex+1,i+1);
        aisleLock[i].Release();
        break;
      }
      aisleLock[i].Release();
      if(i==MAX_AISLES-1)//NO more items to be restocked
        reStockAisle=-1;
    }
  }   
}


void manager()
{
  bool getTheMoney[MAX_CR];
  int totalSale=0;
  //used to check if it needs to withdraw the money from CR
  while(1)
  { //check if it needs more clerks
    
    managerLock.Acquire();
    for(int i=0;i<MAX_CLERKS;i++)
    {
      if(moreClerk[i]==0)
        continue;
      else//clerk calls manager
      { 
        for(int j=i;j<MAX_CLERKS;j++)
	{
          if(moreClerk[j]==1)
	  {
            printf("Manager got a call from Clerk [%d].\n",j+1);
            moreClerk[j]=0;
          }
        }
        for(int j=0;j<MAX_CLERKS;j++)
        {
          if(clerkState[j]==1)
  	  {
            printf("Manager wakes up Clerk.\n");
            clerkState[j]=0;
            clerkBreakCV[j].Signal(&managerLock);
            break;
          }
        }
      }
    }
    managerLock.Release();

    managerLock.Acquire();
    if(noClerk>0)//there is at least one customer calls manager
    {
      for(int i=0;i<MAX_CLERKS;i++)
      {
        if(clerkState[i]==1)
	{
          printf("Manager wakes up Clerk for customer's call.\n");
          clerkState[i]=0;
          clerkBreakCV[i].Signal(&managerLock);
          break;
        }
      }
      for(int j=0;j<noClerk;j++)
      {
        noClerkCV.Signal(&managerLock);
      }
      noClerk=0;
    }
    managerLock.Release(); 
    
    // check if manager needs money
    for(int i=0;i<MAX_CR;i++)
    {
      cashRegisterLock[i].Acquire();
      if(noMoney[i]==1)//some CR needs money
      {
        int balance=totalPrice[i]-moneyInDrawer[i];
        moneyInDrawer[i]+=balance;
        noMoney[i]=0;
        needMoneyCV[i].Signal(&cashRegisterLock[i]);
        printf("Manager gave $[%d] to cash register [%d].\n",balance,i+1);
      }
      cashRegisterLock[i].Release();
    }
   
    //check service button-ask stockboy to find customer
    managerLock.Acquire();
    if(serviceButton==1)
    {
      sbStatusLock.Acquire();
      for(int i=0;i<MAX_STOCKBOYS;i++)
      {
        if(sbStatus[i]==-1)
	{
          myAisle[i]=100;
          printf("Manager wakes up StockBoy.\n");
          sbStatus[i]=-2;
          sbWakeCV[i].Signal(&sbStatusLock);  //wake up stockboy
          break; 
        }
      }
      serviceButton=0;
      sbStatusLock.Release();
    }
    managerLock.Release();

    //check if any customer wants to buy a item, but the shelf is empty
    for(int i=0;i<MAX_AISLES;i++)
    {
      aisleLock[i].Acquire();
      if(needSB[i]==1)
      {
        sbStatusLock.Acquire();
        for(int j=0;j<MAX_STOCKBOYS;j++)
	{
          if(sbStatus[j]==-1)
	  {
            myAisle[j]=i;
            printf("Manager wakes up StockBoy.\n");
            sbStatus[j]=-2;
            sbWakeCV[j].Signal(&sbStatusLock);  //wake up stockboy
            break; 
          } 
        }
        sbStatusLock.Release();
        needSB[i]=0;
      }
      aisleLock[i].Release();
    }

    //check if there is any shelf need to be restocked
    for(int i=0;i<MAX_AISLES;i++)
    {
      aisleLock[i].Acquire();
      if(itemOnAisle[i]<COUNT_FLOOR)
      {
        sbStatusLock.Acquire();
        for(int j=0;j<MAX_STOCKBOYS;j++)
	{
          if(sbStatus[j]==-1)
	  {
            myAisle[j]=i;
            printf("Manager wakes up StockBoy.\n");
            sbStatus[j]=-2;
            sbWakeCV[j].Signal(&sbStatusLock);  //wake up stockboy
            break; 
          } 
        }
        sbStatusLock.Release();
      }
      aisleLock[i].Release();
    }
    srand(seed*2);
    for(int i=0;i<MAX_CR;i++)
    {
      int rn=(rand()%2);
      if(rn==0)
        getTheMoney[i]=TRUE;
      else
        getTheMoney[i]=FALSE;
    }   
    for(int i=0;i<MAX_CR;i++)
    {
      cashRegisterLock[i].Acquire();
      //the clerk is scanning item
      if(start_scanning[i]==1)
      {
        cashRegisterLock[i].Release();    
      }
      //the CR is not being using
      else
      { 
        if(getTheMoney[i]==FALSE)
          cashRegisterLock[i].Release();
        
        else if(withDraw[i]==1)        
          cashRegisterLock[i].Release();
        else//go get the money from drawer
	{ 
          //withdraw money from CR
	  
          totalSale+=crSale[i];
          crSale[i]=0;
          moneyInDrawer[i]=0;
          withDraw[i]=1;
          printf("Manager emptied Cash Register [%d] drawer.\n", i+1);
          printf("Manager has total sale of $[%d].\n",totalSale);
          cashRegisterCV[i].Signal(&cashRegisterLock[i]);            
          cashRegisterLock[i].Release();
          
        }
      }
    }
    srand(seed+100);
    if((rand()%10)>=5)
      printf("-------Total Sale of the entire store until now is $[%d]---------\n",totalSale);
    //=====================check if it's time to close===================    
    int closeStore=1;
    sbStatusLock.Acquire();
    for(int j=0;j<MAX_STOCKBOYS;j++)
    {
      if(sbStatus[j]!=-1) //stockboy is still working
      { 
        closeStore=0;
        break;
      }    
    } 
    sbStatusLock.Release();
    
    for(int i=0;i<MAX_CR;i++)//if all customer are gone,withdraw all the money
    { 
      if(closeStore==0)
        break; 
     
      cashRegisterLock[i].Acquire();
      if(customerInStore!=0)//if there is still customer in the store
      {
        cashRegisterLock[i].Release();
        break;
      }
             
 
      totalSale+=crSale[i];
      crSale[i]=0;
      moneyInDrawer[i]=0;
      withDraw[i]=1;
      printf("Manager emptied Cash Register [%d] drawer.\n", i+1);
      printf("Manager has total sale of $[%d].\n",totalSale);
      cashRegisterCV[i].Signal(&cashRegisterLock[i]);
        
      cashRegisterLock[i].Release();
      if(i==MAX_CR-1)//end simulation
      {
        printtheResult();
        return;
      }
    }
    //================================
  }  
}

void generate_item(int &noti, int &noit, int &tempM,int *item, int index)
{  
  srand(seed*seed+index);
  
  int rn;
  int toss;
  
  for(int i=0;i<MAX_ITEM_TYPES;i++)
  { 
    toss=(rand()%10);
    if(toss>=5)
      continue;

    noti++;
    rn=(rand()%10);
    item[rn]++;
    tempM+=price[rn];
    if(item[rn]==1)
      noit++;
  } 
}

void generate_price()
{
  srand(seed*3);
  for(int i=0;i<MAX_ITEM_TYPES;i++)
    price[i]=(rand()%MAX_PRICE)+1;
}

void printInitialStatement()
{
  printf("Number of Clerks = [%d].\n",MAX_CLERKS);
  printf("Number of StockBoys = [%d].\n",MAX_STOCKBOYS);
  printf("Number of CashRegisters = [%d].\n",MAX_CR);
  printf("Number of Customers = [%d].\n",CUSTOMER_NUM);
  printf("Number of Managers = [1].\n");
  printf("Number of Aisle = [%d].\n",MAX_AISLES);
  printf("  Items:\n");
  printf("    Number-Price\n");
  for(int i=0;i<MAX_ITEM_TYPES;i++)
    printf("    [%d]-$[%d]\n",i+1,price[i]);
}

void printtheResult()
{
  int totalSaleStore=0;
  for(int j=0;j<MAX_CR;j++)
  {
    printf("Total Sale from Cash Register [%d] is $[%d].\n",
	   j+1,crTotalSale[j]);
    totalSaleStore+=crTotalSale[j];
  }
  printf("Total Sale of the entire store is $[%d].\n",totalSaleStore);  
}

void Problem2()
{
  
  generate_price();
 
  printInitialStatement();
  
  Thread *m;
  Thread *thread_customer;
  Thread *thread_clerk;
  Thread *thread_stockboy;
  Thread *thread_cashRegister;
  printf("Starting Test\n");

  m = new Thread("manager");
  m->Fork((VoidFunctionPtr)manager,0);

  for(int i=0;i<MAX_STOCKBOYS;i++){
    char name[10];
    sprintf(name,"stockboy%d",i+1);
    thread_stockboy = new Thread(name);
    thread_stockboy->Fork((VoidFunctionPtr)stockboy ,i);
  }

  for(int i=0;i<CUSTOMER_NUM;i++){
    char name[10];
    sprintf(name,"customer%d",i+1);
    thread_customer = new Thread(name);
    thread_customer->Fork((VoidFunctionPtr)customer ,i);
  }
 
  for(int i=0;i<MAX_CR;i++){
    char name[10];
    sprintf(name,"cashRegister%d",i+1);
    thread_cashRegister = new Thread(name);
    thread_cashRegister->Fork((VoidFunctionPtr)cashRegister ,i);
  }
 
  for(int i=0;i<MAX_CLERKS;i++){
    char name[10];
    sprintf(name,"clerk%d",i+1);
    thread_clerk = new Thread(name);
    thread_clerk->Fork((VoidFunctionPtr)clerk ,i);
  }  
 
}
